#region imported Namespaces
using System;
using System.Data;
using System.Data.SqlClient;

using BO = PHSRAG.Insight21.BusinessObjects;
using Utility = PHSRAG.Utility;
using ICachePolicy = PHSRAG.Insight21.Policy.ICachePolicy;
using GenerateKey = PHSRAG.Insight21.BusinessObjects.ModuleKey;
#endregion

namespace PHSRAG.Insight21.Admin
{
	/// <summary>
	/// User holds domain and application user information.  The user
	/// contact details can be saved to the database.
	/// </summary>
	public class User : BO.SaveableBusinessObject
	{
		#region Constants
		private static string UserKey = GenerateKey.MakeKey("User_67EBF23B-27D0-4c2b-BC42-B2BF777DDF2F",GenerateKey.Admin);
		private const string UserTableName = "User";
		#endregion

		#region Instance Variables
		/// <summary>The user's profile information including contact details.</summary>
		private UserDetails userDetails;
		/// <summary>The user's module access rights.</summary>
		private Modules userModuleAccess;
		/// <summary>The user's module roles.</summary>
		private ModuleRoles userModuleRoleAccess;
		/// <summary>The user's direct (record) access rights.</summary>
		private DirectAccessRights directAccessRights;
		/// <summary>The user's organization access rights.</summary>
		private OrganizationAccessRights organizationAccessRights;
		/// <summary>The user's portfolio access rights.</summary>
		private PortfolioAccessRights portfolioAccessRights;
		/// <summary>The user's application user info.</summary>
		private ApplicationUser applicationUser;
		#endregion

		#region Public Properties
		/// <summary>
		/// Get the key to be used in all caching operations for this instance of the object.
		/// </summary>
		public static string CacheKey	{ get { return UserKey; } }

		/// <summary>Get's the user's application user id from the underlying DataContainer.
		/// If the user is not an application user the value is null so 0 is returned.</summary>
		public int ApplicationUserId 
		{
			get 
			{ 
				object o = DataContainer.Tables[UserTableName].Rows[0]["ApplicationUserId"];
				return (o == DBNull.Value) ? 0 : (int)o;
			}
		}

		/// <summary>Get's the Doamin Status data from the underlying DataContainer and returns
		/// "Active" if the user is is active on the domain, otherwise returns "Inactive".</summary>
		public string DomainStatus
		{
			get 
			{
				return (bool)DataContainer.Tables[UserTableName].Rows[0]["DomainStatus"] ? "Active" : "Inactive";
			}
		}

		/// <summary>Get's the user's domain user id from the underlying DataContainer.</summary>
		/// Try to get the domainuserid (internals have this) if not, this means the person is external
		/// So get the PersonId. 
		public int DomainUserId 
		{
			get 
			{ 
				try 
				{
					return (int)DataContainer.Tables[UserTableName].Rows[0]["DomainUserId"];
				}
				catch
				{
					 return (int)DataContainer.Tables[UserTableName].Rows[0]["PersonId"];
				}

			}
		}

		/// <summary>Get's the user's domain user id from the underlying DataContainer.</summary>
		public string FirstName
		{
			get 
			{ 
				return (string)DataContainer.Tables[UserTableName].Rows[0]["FirstName"];
			}
		}

		/// <summary>Get's the registered data from the underlying DataContainer.</summary>
		public bool IsRegistered
		{
			get 
			{
				return Convert.ToBoolean((int)DataContainer.Tables[UserTableName].Rows[0]["Registered"]);
			}
		}

		/// <summary>Get's the user's last name from the underlying DataContainer.</summary>
		public string LastName
		{
			get 
			{ 
				return (string)DataContainer.Tables[UserTableName].Rows[0]["LastName"];
			}
		}

		/// <summary>Get's the user's organization name from the underlying DataContainer.</summary>
		public string Organization
		{
			get 
			{ 
				return (string)DataContainer.Tables[UserTableName].Rows[0]["Organization"];
			}
		}

        /// <summary>Get's the user's organization id from the underlying DataContainer.</summary>
        public int OrganizationId
        {
            get 
            { 
                return (int)DataContainer.Tables[UserTableName].Rows[0]["OrganizationId"];
            }
        }

		/// <summary>Get's the user's person id from the underlying DataContainer.</summary>
		public int PersonId 
		{
			get 
			{ 
				return (int)DataContainer.Tables[UserTableName].Rows[0]["PersonId"];
			}
		}


		/// <summary>Get's the user's domain usernamefrom the underlying DataContainer.</summary>
		public string Username
		{
			get 
			{ 
				return (string)DataContainer.Tables[UserTableName].Rows[0]["Username"];
			}
		}

		#endregion

		#region Public Contained Objects
		/// <summary>
		/// Gets the User's UserDetails object.  If the object is null, it is loaded then returned.
		/// </summary>
		public UserDetails Details
		{
			get 
			{
				if ( userDetails == null )
				{		
					userDetails = new UserDetails(DataContainer, CachePolicy);
					try
					{
						userDetails.Load( Utility.DataAccess.ConnectionString, PersonId );
					}
					catch(Exception e)
					{
						throw e;
					}
				}
				return userDetails;
			}
			
		}

		/// <summary>
		/// Gets the User's Modules object.  If the object is null, it is loaded then returned.
		/// </summary>
		public Modules ModuleAccess
		{
			get 
			{
				if ( userModuleAccess == null )
				{		
					userModuleAccess = new Modules(DataContainer, CachePolicy);
					try
					{
						userModuleAccess.Load( Utility.DataAccess.ConnectionString, ModulesCommandType.GetUserModules, ApplicationUserId );
					}
					catch(Exception e)
					{
						throw e;
					}
				}
				return userModuleAccess;
			}
			
		}

		/// <summary>
		/// Gets the User's ModuleRoles object.  If the object is null, it is loaded then returned.
		/// </summary>
		public ModuleRoles ModuleRolesAccess
		{
			get 
			{
				if ( userModuleRoleAccess == null )
				{		
					userModuleRoleAccess = new ModuleRoles(DataContainer, CachePolicy);
					try
					{
						userModuleRoleAccess.Load( Utility.DataAccess.ConnectionString, ApplicationUserId );
					}
					catch(Exception e)
					{
						throw e;
					}
			}
				return userModuleRoleAccess;
			}
			
		}

		/// <summary>
		/// Gets the User's Application User object.  If the object is null, it is loaded then returned.
		/// </summary>
		public ApplicationUser ApplicationUserDetail
		{
			get 
			{
				if ( applicationUser == null )
				{		
					applicationUser = new ApplicationUser (CachePolicy);
					try
					{
						applicationUser.Load( Utility.DataAccess.ConnectionString, DomainUserId );
					}
					catch(Exception e)
					{
						throw e;
					}
				}
				return applicationUser;
			}
		}

		#endregion

		#region Constructor
		/// <summary>
		/// Initialize the state of this object and create commands to handle insert/delete/update.
		/// </summary>
		public User(ICachePolicy cachePolicy) : base(cachePolicy)
		{
			DataContainer = new DataSet();
		}
		#endregion

		#region Public Methods

		/// <summary>
		/// Gets the User's Direct Record Rights object.  If the object is null, it is loaded then returned.
		/// </summary>
		public DirectAccessRights GetDirectAccessRights(int piDomainUserId, int keyGiverDomainUserId)
		{
			if ( directAccessRights == null )
			{		
				directAccessRights = new DirectAccessRights(DataContainer, CachePolicy);
				try
				{
					directAccessRights.Load( Utility.DataAccess.ConnectionString, DomainUserId, piDomainUserId, keyGiverDomainUserId );
				}
				catch(Exception e)
				{
					throw e;
				}
			}
			return directAccessRights;
		}

		/// <summary>
		/// Gets the User's Organization Rights object.  If the object is null, it is loaded then returned.
		/// </summary>
		/// <param name="args">can optionally pass KeyGiver's DomainUserId to be used 
		/// to load the user's access rights to the keygiver's organizations.</param>
		public OrganizationAccessRights GetOrganizationRights (int keyGiverDomainUserId )
		{
			if ( organizationAccessRights == null )
			{		
				organizationAccessRights = new OrganizationAccessRights(DataContainer, CachePolicy);
				try
				{
					organizationAccessRights.Load( Utility.DataAccess.ConnectionString, DomainUserId, keyGiverDomainUserId);
				}
				catch(Exception e)
				{
					throw e;
				}
			}
			return organizationAccessRights;
		}

		/// <summary>
		/// Gets the User's Portfolio Rights object.  If the object is null, it is loaded then returned.
		/// </summary>
		/// <param name="args">can optionally pass PIDomainUserId to be used 
		/// to load the user's access rights to that PI's portfolio.</param>
		/// <returns></returns>
		public PortfolioAccessRights GetPortfolioRights(int piDomainUserId )
		{
			if ( portfolioAccessRights == null )
			{
				portfolioAccessRights = new PortfolioAccessRights(DataContainer, CachePolicy);
				try
				{
					portfolioAccessRights.Load( Utility.DataAccess.ConnectionString, DomainUserId, piDomainUserId);
				}
				catch(Exception e)
				{
					throw e;
				}
			}
			return portfolioAccessRights;
		}

		#endregion

		#region Base Methods
		/// <summary>Caches this object based on its caching policy.</summary>
		public override void Cache()
		{
			CachePolicy.Cache(CacheKey, this);
		}

		/// <summary>UnCaches this object based on its caching policy.</summary>
		public override void UnCache()
		{
			CachePolicy.UnCache(CacheKey);
		}

		/// <summary>
		/// Expects a valid person id to be used to load this user object's
		/// DataContainer by calling the GetUser stored procedure in the database.
		/// If a person id is not specified an Exception is thrown. 
		/// </summary>
		/// <param name="connectionString">Valid database connection string.</param>
		/// <param name="args">The person id to be used to load the user object.</param>
		public override void Load( string connectionString, params object[] args )
		{
			if ( args.Length != 1 )
			{
				throw new Exception ("User Load expects Person ID." );
			}

			int personId = (int)args[0];

			try
			{
				DataContainer.Reset();
			
				Utility.DataAccess.LoadDataSet(DataContainer, UserTableName, connectionString,
					"GetUser", Utility.DataAccess.BuildSqlParameterArray("@personId" ,SqlDbType.Int, personId));
				
				if (!DataContainer.Tables.Contains(UserTableName) || DataContainer.Tables[0].Rows.Count == 0)
				{
					Utility.DataAccess.LoadDataSet(DataContainer, UserTableName, connectionString, 
						"GetExternalUser", Utility.DataAccess.BuildSqlParameterArray("@personId" ,SqlDbType.Int, personId));
				}

				if ( !DataContainer.Tables.Contains(UserTableName) || DataContainer.Tables[0].Rows.Count == 0)
					throw new Exception("Failed to load user information.");

			}
			catch( Exception e)
			{
				Utility.ExceptionReport.WriteToEventLog ("User Load", e, true, Utility.ExceptionReport.ReportType.Error);
				throw e;
			}
		}

		/// <summary>
		/// Persists the user's Details state to database.
		/// </summary>
		/// <param name="connectionString">Specifies database connection information</param>
		public override void Save(string connectionString, params object[] args)
		{
			Details.Save(connectionString);
		}


		/// <summary>
		/// Updates the user's entries in the User Resource Cache table in the database,
		/// based on the user's current access rights in the database.
		/// </summary>
		/// <param name="connectionString">Specifies database connection information</param>
		public void UpdateUserResourceCache(SqlTransaction transaction)
		{
			Utility.DataAccess.ExecuteNonQuery(
                transaction.Connection,
				transaction,
				"UpdateUserResourceCache",
				Utility.DataAccess.BuildSqlParameterArray("@domainUserId", SqlDbType.Int, DomainUserId));
		}
		#endregion

	}
}
